package com.edfeff.nio.simple;

import com.edfeff.bio.http.StsException;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioSimpleHttpServer {
    private ServerSocketChannel socketChannel;
    private Selector selector;
    private final int port;
    private volatile boolean run = false;

    public NioSimpleHttpServer(int port) {
        this.port = port;
        init();
    }

    private void init() {
        try {
            selector = Selector.open();
            socketChannel = ServerSocketChannel.open();
            socketChannel.bind(new InetSocketAddress(port));
            socketChannel.configureBlocking(false);
            socketChannel.register(selector, SelectionKey.OP_ACCEPT);
            this.run = true;
        } catch (IOException e) {
            e.printStackTrace();
            throw new StsException("启动失败");
        }
    }

    public void start() throws IOException {
        System.out.println("Nio服务器 启动！");
        while (run) {
            try {
                System.out.println("等待连接中...");//这里是阻塞的！
                int n = selector.select(1000);
                if (n == 0) {
                    continue;
                }
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> keyIt = keys.iterator();
                while (keyIt.hasNext()) {
                    SelectionKey key = keyIt.next();
                    if (key.isAcceptable()) {
                        System.out.println(Thread.currentThread().getName() + " isAcceptable..");
                        acceptConnection(key);
                    } else if (key.isReadable()) {
                        System.out.println(Thread.currentThread().getName() + " isReadable..");
                        readData(key);
                    }
                    keyIt.remove();
                }
            } catch (IOException e) {
                e.printStackTrace();
                run = false;
            }
        }
    }

    private void acceptConnection(SelectionKey key) throws IOException {
        ServerSocketChannel server = (ServerSocketChannel) key.channel();
        SocketChannel client = server.accept();
        client.configureBlocking(false);
        client.register(selector, SelectionKey.OP_READ);
    }

    private void readData(SelectionKey key) throws IOException {
        SocketChannel client = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int bytesRead = client.read(buffer);
        if (bytesRead > 0) {
            String requestData = new String(buffer.array(), 0, bytesRead);
            System.out.println(Thread.currentThread().getName() + "-> Received request: " + requestData);
            String responseData = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<html><body><h1>Hello, World!</h1></body></html>";
            buffer = ByteBuffer.wrap(responseData.getBytes());
            client.write(buffer);
        }
        client.close();
    }

    public static void main(String[] args) throws IOException {
        new NioSimpleHttpServer(8080).start();
    }

}
